package com.handong.handserialprogram.voice;

import android.content.Context;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Build;

import com.handong.handserialprogram.R;

import java.util.LinkedList;
import java.util.ListIterator;


/**
 * 发声模块。
 * Created by userKey on 2017/11/21.
 */

public class VoiceImpl {

    private static VoiceImpl mImpl;

    private Context mContext;
    private SoundPool mSoundPool;
    private int[] mSoundRes;
    private LinkedList<VoiceImpl.Entry> mResList;

    private VoiceImpl(Context context) {
        mContext = context.getApplicationContext();
        init();
    }

    public static VoiceImpl getInstance(Context context) {
        if (mImpl == null) {
            synchronized (VoiceImpl.class) {
                if (mImpl == null) {
                    mImpl = new VoiceImpl(context);
                }
            }
        }
        return mImpl;
    }

    private void init() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            mSoundPool = new SoundPool(1, AudioManager.STREAM_SYSTEM, 0);
        } else {
            mSoundPool = new SoundPool.Builder()
                    .setMaxStreams(1)
                    .build();
        }
        mSoundRes = new int[9];
        if (mResList == null)
            mResList = new LinkedList<>();
    }

    public boolean isRest(){
        if (mSoundPool == null || mResList.isEmpty()){
            return true;
        }
        return false;
    }

    public void addSound(final int res) {
        VoiceImpl.Entry entry = getEntry(res);
        if (null != entry) {//已存在，不处理。
            return;
        }
        if (mSoundPool == null) init();
        if (0 == mSoundRes[0]) {
            mSoundRes[0] = res;
            mSoundPool.load(mContext, res, 1);
            mSoundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
                @Override
                public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
                    if (1 == sampleId) {
                        soundPool.play(sampleId, 1f, 1f, 0, 0, 1f);
                        soundPool.setOnLoadCompleteListener(null);
                        autoLoad(soundPool, res);
                    }
                }
            });
            return;
        }
        int loaded = isLoad(res);//二级缓存。
        entry = new VoiceImpl.Entry(res);
        entry.loaded = loaded;//一级缓存。
        mResList.add(entry);
//        if (R.raw.warning_exception == res || R.raw.warning_escape == res || R.raw.warning_ring_low_power == res) {
//            mResList.add(entry);
//        } else {
//            mResList.addFirst(entry);
//        }
    }

    private void autoLoad(SoundPool soundPool, int first) {
        int[] temp = new int[]{R.raw.warning_ring_broken, R.raw.warning_lock_open, R.raw.warning_ring_low_power,
                R.raw.warning_escape, R.raw.warning_exception,R.raw.warnning_phone_fence_out,R.raw.info_phone_fence_normal,R.raw.info_new_message};
        int index = 1;
        int[] res = mSoundRes;
        for (int i = 0; i < temp.length; i++) {
            if (first != temp[i]) {
                res[index++] = temp[i];
                soundPool.load(mContext, temp[i], 1);
            }
        }
    }

    public void playHighPriority(int res) {
        int loaded = isLoadAndPlay(res);//二级缓存。
        if (loaded == -1) {
            final int temp = mSoundPool.load(mContext, res, 0);
            mSoundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
                @Override
                public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
                    if (temp == sampleId) {
                        soundPool.play(sampleId, 1f, 1f, 2, 0, 1f);
                        soundPool.setOnLoadCompleteListener(null);
                    }
                }
            });
        } else {
            synchronized (VoiceImpl.class) {
                mSoundPool.play(loaded, 1f, 1f, 2, 0, 1f);
            }
        }
    }

    private VoiceImpl.Entry getEntry(int res) {
        LinkedList<VoiceImpl.Entry> list = mResList;
        if (list.isEmpty()) {
            return null;
        }
//        if (list.size() == 1) {
//            return list.getFirst();
//        }
        ListIterator<VoiceImpl.Entry> iterator = list.listIterator();
        VoiceImpl.Entry entry = null;
        while (iterator.hasNext()) {
            entry = iterator.next();
            if (res == entry.res) {
                return entry;
            }
        }
        return null;
    }

    private int isLoad(int resId) {
        int len = mSoundRes.length;
        for (int i = 0; i < len; i++) {
            if (0 == mSoundRes[i]) {
                break;
            }
            if (resId == mSoundRes[i]) {
                return i + 1;
            }
        }
        return -1;
    }

    private int isLoadAndPlay(int resId) {
        if (mSoundPool == null) init();
        int len = mSoundRes.length;
        for (int i = 0; i < len; i++) {
            if (0 == mSoundRes[i]) {
                mSoundRes[i] = resId;
                return -1;
            }
            if (resId == mSoundRes[i]) {
                return i + 1;
            }
        }
        return -1;
    }

    public boolean playVoice() {
        if (mResList.isEmpty()) {
            return false;
        }
        VoiceImpl.Entry entry = mResList.pollFirst();
        int loaded = entry.loaded;
        if (loaded == -1) {
            int[] temp = mSoundRes;
            for (int i = 0; i < temp.length; i++) {
                if (temp[i] == 0) {
                    break;
                }
                if (entry.res == temp[i]) {
                    loaded = i + 1;
                    break;
                }
            }
        }
        if (loaded == -1) {
            mResList.add(entry);
            return false;
        }
        synchronized (VoiceImpl.class) {
            mSoundPool.play(loaded, 1f, 1f, 0, 0, 1f);
            return true;
        }
    }

    public void removeVoice(int res) {
        if (mResList.isEmpty()) {
            return;
        }
        LinkedList<VoiceImpl.Entry> list = mResList;
        ListIterator<VoiceImpl.Entry> iterator = list.listIterator();
        while (iterator.hasNext()) {
            if (res == iterator.next().res) {
                iterator.remove();
                break;
            }
        }
    }

    public void releaseRes() {
        if (mSoundPool != null) {
            mSoundPool.release();
            mSoundPool = null;
        }
        mResList.clear();
        mSoundRes = null;
    }

    static class Entry {

        private int res = 0;
        private int loaded = 0;


        public Entry(int res) {
            this.res = res;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof VoiceImpl.Entry) {
                VoiceImpl.Entry entry = (VoiceImpl.Entry) obj;
                if (entry.res == this.res) {
                    return true;
                }
            }
            return false;
        }

        @Override
        public String toString() {
            return "Entry : " + " || " + res + " || " + loaded;
        }
    }
}
